package com.micro.platform.oauth.controller.token;

import com.micro.platform.oauth.dto.TokenInfoDTO;
import com.micro.platform.oauth.enums.OauthErrorCodeEnum;
import com.micro.platform.oauth.framework.OauthManager;
import com.micro.platform.oauth.framework.domain.AccessToken;
import com.micro.platform.oauth.framework.domain.OauthRequest;
import com.micro.platform.oauth.framework.exception.OauthException;
import com.micro.platform.starter.domain.Result;
import com.micro.platform.starter.exception.BusinessException;
import com.micro.platform.starter.utils.BeanCopyUtil;
import com.micro.platform.starter.utils.MapUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.util.Collections;
import java.util.List;
import java.util.Map;

@Api(tags = "token管理")
@RestController
@RequestMapping("/token")
public class TokenController {
    @Autowired
    private OauthManager oauthManager;

//    @ApiOperation(value = "登录")
//    @PostMapping("/login")
//    public Result<TokenLoginResponse> login(@RequestBody TokenLoginRequest request) {
//        AccessToken accessToken;
//        try{
//            OauthRequest oauthRequest = BeanCopyUtil.copyProperties(request, OauthRequest::new);
//            accessToken = oauthManager.login(oauthRequest);
//        }catch (OauthException ex){
//            throw new BusinessException(OauthErrorCodeEnum.AUTHENTICATION_ERROR, ex);
//        }
//        TokenLoginResponse tokenLoginResponse = buildTokenLoginResponse(accessToken);
//        return Result.ok(tokenLoginResponse);
//    }

    @ApiOperation(value = "密码登录")
    @PostMapping("/loginPassword")
    public Result<TokenLoginResponse> loginPassword(@RequestBody @Validated TokenLoginPasswordRequest request) {
        AccessToken accessToken;
        try{
            OauthRequest oauthRequest = BeanCopyUtil.copyProperties(request.toTokenLoginRequest(), OauthRequest::new);
            accessToken = oauthManager.login(oauthRequest);
        }catch (OauthException ex){
            throw new BusinessException(OauthErrorCodeEnum.AUTHENTICATION_ERROR, ex);
        }
        TokenLoginResponse tokenLoginResponse = buildTokenLoginResponse(accessToken);
        return Result.ok(tokenLoginResponse);
    }

    @ApiOperation(value = "刷新登录")
    @PostMapping("/loginRefresh")
    public Result<TokenLoginResponse> loginRefresh(@RequestBody @Validated TokenLoginRefreshRequest request) {
        AccessToken accessToken;
        try{
            OauthRequest oauthRequest = BeanCopyUtil.copyProperties(request.toTokenLoginRequest(), OauthRequest::new);
            accessToken = oauthManager.login(oauthRequest);
        }catch (OauthException ex){
            throw new BusinessException(OauthErrorCodeEnum.AUTHENTICATION_ERROR, ex);
        }
        TokenLoginResponse tokenLoginResponse = buildTokenLoginResponse(accessToken);
        return Result.ok(tokenLoginResponse);
    }

    @ApiOperation(value = "信息")
    @PostMapping("/info")
    public Result<TokenLoginResponse> info(@RequestHeader("access-token") String token) {
        AccessToken accessToken;
        try{
            accessToken = oauthManager.getAccessToken(token);
        }catch (OauthException ex){
            throw new BusinessException(OauthErrorCodeEnum.AUTHENTICATION_ERROR, ex);
        }
        TokenLoginResponse tokenLoginResponse = buildTokenLoginResponse(accessToken);
        return Result.ok(tokenLoginResponse);
    }

    @ApiOperation(value = "内部信息")
    @GetMapping("/private-info")
    public Result<TokenInfoDTO> privateInfo(@RequestParam("access-token") String accessToken) {
        AccessToken accessTokenObj;
        try{
            accessTokenObj = oauthManager.getAccessToken(accessToken);
        }catch (OauthException ex){
            throw new BusinessException(OauthErrorCodeEnum.AUTHORIZATION_ERROR, ex);
        }
        if(accessTokenObj == null){
            return Result.ok(null);
        }
        Map<String, Object> data = accessTokenObj.getData();
        TokenInfoDTO tokenInfoDTO = new TokenInfoDTO();
        tokenInfoDTO.setUserId(MapUtils.getLong(data, "userId"));
        tokenInfoDTO.setNickName(MapUtils.getString(data, "nickName"));
        tokenInfoDTO.setPhone(MapUtils.getString(data, "phone"));
        tokenInfoDTO.setEmail(MapUtils.getString(data, "email"));
        tokenInfoDTO.setPrivateKey(MapUtils.getString(data, "privateKey"));
        tokenInfoDTO.setPublicKey(MapUtils.getString(data, "publicKey"));
        tokenInfoDTO.setCreateTime(MapUtils.getString(data, "createTime"));
        List<String> apis = MapUtils.getArrayList(data, "apis", String.class);
        if(apis == null){
            apis = Collections.emptyList();
        }
        tokenInfoDTO.setApis(apis);
        return Result.ok(tokenInfoDTO);
    }

    @ApiOperation(value = "登出")
    @PostMapping("logout")
    public Result<Boolean> logout(@RequestHeader("access-token") String accessToken) {
        oauthManager.logout(accessToken);
        return Result.ok("成功登出");
    }

    private TokenLoginResponse buildTokenLoginResponse(AccessToken accessToken) {
        TokenLoginResponse tokenLoginResponse = new TokenLoginResponse();
        tokenLoginResponse.setAccessToken(accessToken.getAccessToken());
        tokenLoginResponse.setExpiresTime(accessToken.getExpiresTime());
        tokenLoginResponse.setExpiresTimeStamp(accessToken.getExpiresTimeStamp());
        tokenLoginResponse.setRefreshToken(accessToken.getRefreshToken());
        tokenLoginResponse.setRefreshExpiresTime(accessToken.getRefreshExpiresTime());
        tokenLoginResponse.setAccount(accessToken.getAccount());
        tokenLoginResponse.setClientId(accessToken.getClientId());
        tokenLoginResponse.setScopes(accessToken.getScopes());
        Map<String, Object> data = accessToken.getData();
        if(CollectionUtils.isEmpty(data)){
            return tokenLoginResponse;
        }
        tokenLoginResponse.setUserId(MapUtils.getLong(data, "userId"));
        tokenLoginResponse.setNickName(MapUtils.getString(data, "nickName"));
        tokenLoginResponse.setPhone(MapUtils.getString(data, "phone"));
        tokenLoginResponse.setEmail(MapUtils.getString(data, "email"));
        tokenLoginResponse.setCreateTime(MapUtils.getString(data, "createTime"));
        tokenLoginResponse.setRoles(MapUtils.getArrayList(data, "authorities", String.class));
        return tokenLoginResponse;
    }
}
